#pragma once
#include "matrix2.h"


#define TEMPLATE template<typename T>
#define MATRIX2 Matrix2T<T>

BEGIN_NAMESPACE_OXGE


TEMPLATE
const MATRIX2 MATRIX2::IDENTITY(1,0,
								0,1);

TEMPLATE
const MATRIX2 MATRIX2::ZERO( 0,0,
							 0,0);


//mat * mat
TEMPLATE
MATRIX2 MATRIX2::operator * (const MATRIX2& matR)const
{
	return MatrixType( RowVector(0).dot(matR.ColVector(0)), RowVector(0).dot(matR.ColVector(1)), 
					   RowVector(1).dot(matR.ColVector(0)), RowVector(1).dot(matR.ColVector(1)) );

}

//mat ^ p
TEMPLATE
inline MATRIX2 MATRIX2::operator^(int p)
{
	MatrixType ret = MatrixType::IDENTITY;
	for(int i=0;i< abs(p) ; ++i)
		ret *= (*this);

	if( p < 0 )
		return ret.GetInverse();

	return ret;
}

//mat * v
TEMPLATE
inline typename MATRIX2::VectorType MATRIX2::operator*(const typename MATRIX2::VectorType& vec)const
{
	return VectorType( RowVector(0).Dot(vec), RowVector(1).Dot(vec) );
}

//transpose src to dest
TEMPLATE
void transpose(MATRIX2& dest, const MATRIX2& src)
{	
	if(&dest != &src)
	{
		dest.m01 = src.m10;
		dest.m10 = src.m01;
		dest.m00 = src.m00;
		dest.m11 = src.m11;
	}
	else
	{
		std::swap(dest.m01, dest.m10);
	}
}

TEMPLATE
bool inverse(MATRIX2& dest, const MATRIX2& src)
{
	T detsrc = src.Det();
	if( detsrc == 0 )
	{
		return false;
	}

	if( &dest != &src )
	{
		dest.m00 = src.m11 / detsrc;
		dest.m01 = -src.m01 / detsrc;
		dest.m10 = -src.m10 / detsrc;
		dest.m11 = src.m00 / detsrc;
	}
	else
	{
		MATRIX2 srcCpy = src;
		dest.m00 = srcCpy.m11 / detsrc;
		dest.m01 = -srcCpy.m01 / detsrc;
		dest.m10 = -srcCpy.m10 / detsrc;
		dest.m11 = srcCpy.m00 / detsrc;
	}
	return true;
}

//I/O
TEMPLATE
std::ostream& operator<<(std::ostream& os, const  MATRIX2& mat)
{
	size_t iRow = 0;	
	for(;iRow < mat.NRow-1;++iRow){
		size_t iCol = 0;
		for(;iCol < mat.NCol-1 ; ++iCol){
			os << mat(iRow, iCol) << "\t";
		}
		os << mat(iRow, iCol);
		os << '\n';
	}
	size_t iCol = 0;
	for(;iCol < mat.NCol-1 ; ++iCol){
		os << mat(iRow, iCol) << "\t";
	}
	os << mat(iRow, iCol);
	os << ';';

	return os;
}

TEMPLATE
void MATRIX2::UnitTest()
{
	MatrixType mat;
	MatrixType mat1 = ZERO;
	MatrixType mat2 = IDENTITY;

	mat1 * mat2;
	mat^3;

}





END_NAMESPACE_OXGE


#undef  TEMPLATE
#undef MATRIX2